#include "jp.h"
#include <QJsonDocument>
#include <QFile>
#include <QJsonObject>
#include <QDebug>
#include <QJsonArray>
#include "field.h"
#include <QUuid>

jp::jp() {}

jp::~jp()
{
    for(auto cit = id2fd.cbegin(); cit != id2fd.cend(); ++cit)
    {
        if(cit.value() != nullptr)
            delete cit.value();
    }
}

bool jp::load(const char * fileName)
{
    QFile loadFile( fileName);
    if (!loadFile.open(QIODevice::ReadOnly)) {
        qWarning("Couldn't open save file.");
        return false;
    }
    QByteArray saveData = loadFile.readAll();
    QJsonDocument loadDoc = QJsonDocument::fromJson(saveData);
    Q_ASSERT(loadDoc.isArray());
    if(loadDoc.isArray())
    {
        QJsonArray allField = loadDoc.array();
        for(int i=0; i<allField.size(); ++i)
        {
            QJsonValue item = allField.at(i);
            Q_ASSERT(item.isObject());
            auto field = load(item.toObject());
            Q_ASSERT(!id2fd.contains(field->getId()));
            id2fd.insert(field->getId(), field);
        }
    }
    return true;
}

namespace
{
static const QLatin1String idAttribute("id");
static const QLatin1String nameTag("name");
static const QLatin1String factorTag("factor");
static const QLatin1String rangeTag("range");
static const QLatin1String unitTag("unit");
static const QLatin1String fieldWidthTag("fieldWidth");
static const QLatin1String precisionTag("precision");
static const QLatin1String dispatchValTag("value");
static const QLatin1String hitValTag("hit");
static const QLatin1String typeAttribute("type");
}

const Field * jp::load(const QJsonObject & obj)
{
    Field *field = new Field;
    Q_ASSERT(obj.contains(typeAttribute));
    for(auto cit = obj.constBegin(); cit != obj.constEnd(); ++cit)
    {
        const QString & key = cit.key();
        const QJsonValue & val = cit.value();
        if(key == typeAttribute)
        {
            Q_ASSERT(val.isString());
            bool ret = field->setType(val.toString());
            Q_ASSERT(ret);
        }
        else if(key == idAttribute)
        {
            Q_ASSERT(val.isString());
            field->setId(val.toString());
        }
        if(key == nameTag)
        {
            Q_ASSERT(val.isString());
            field->setName(val.toString());
        }
        if(key == factorTag)
        {
            Q_ASSERT(val.isDouble());
            field->setFactor(val.toDouble(1.0));
        }
        if(key == dispatchValTag)
        {
            Q_ASSERT(val.isDouble() || val.isString());
            if(val.isDouble())
            {
                field->setFactor(val.toDouble());
            }
            else if(val.isString())
            {
                bool ok = false;
                field->setFactor(val.toString().toInt(&ok, 0));
                Q_ASSERT(ok);
            }
        }
        if(key == hitValTag)
        {
            Q_ASSERT(val.isDouble() || val.isString());
            if(val.isDouble())
            {
                Q_ASSERT(val.toDouble() <= std::numeric_limits<int>::max());
                field->setHitVal(val.toInt());
            }
            else if(val.isString())
            {
                bool ok = false;
                field->setHitVal(val.toString().toInt(&ok, 0));
                Q_ASSERT(ok);
            }
        }
        if(key == unitTag)
        {
            Q_ASSERT(val.isString());
            field->setUnit(val.toString());
        }
        if(key == fieldWidthTag)
        {
            Q_ASSERT(val.isDouble());
            field->setFieldWidth(val.toInt(0));
        }
        if(key == precisionTag)
        {
            Q_ASSERT(val.isDouble());
            field->setPrecision(val.toInt(-1));
        }
        if(key == "bit")
        {
            Q_ASSERT(val.isArray());
            // @todo
        }
    }
    if(field->getId().isEmpty())
    {
        field->setId(QUuid::createUuid().toString());
    }
    return field;
}

